package com.dbflow5.rx2.query;

import com.dbflow5.BaseUnitTest;
import com.dbflow5.config.FlowManager;
import com.dbflow5.database.DatabaseStatement;
import com.dbflow5.database.DatabaseWrapper;
import com.dbflow5.database.FlowCursor;
import com.dbflow5.models.SimpleModel_Table;
import com.dbflow5.models.SimpleTestModels.SimpleModel;
import com.dbflow5.query.SQLite;
import com.dbflow5.query.property.Property;
import com.dbflow5.reactivestreams.transaction.TransactionObservable;
import com.dbflow5.structure.Model;
import com.dbflow5.transaction.Transaction;

import io.reactivex.rxjava3.functions.Consumer;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;

import static org.junit.Assert.assertEquals;

public class RXQueryTests extends BaseUnitTest {
    @Test
    public void testCanQuery() {
        FlowManager.databaseForTable(SimpleModel.class, db -> {
            Model.save(SimpleModel.class, new SimpleModel("Name"), db);

            AtomicReference<FlowCursor> cursor = new AtomicReference<>();

            Transaction.Builder<FlowCursor> builder = db.beginTransactionAsync((Function<DatabaseWrapper, FlowCursor>) db1 -> SQLite.select().from(SimpleModel.class).cursor(db1));

            TransactionObservable.asMaybe(builder).subscribe(flowCursor -> {
                cursor.set(flowCursor);
            });

            assertEquals(1, cursor.get().getRowCount());
            cursor.get().close();
            return null;
        });
    }

    @Test
    public void testCanCompileStatement() {
        final DatabaseStatement[] databaseStatement = {null};
        FlowManager.databaseForTable(SimpleModel.class, db -> {
            TransactionObservable.asSingle(db.beginTransactionAsync(new Function<DatabaseWrapper, DatabaseStatement>() {
                @Override
                public DatabaseStatement apply(DatabaseWrapper databaseWrapper) {
                    return SQLite.insert(SimpleModel.class, SimpleModel_Table.name.is("name")).compileStatement(databaseWrapper);
                }
            })).subscribe(statement -> databaseStatement[0] = statement);
            databaseStatement[0].close();
            return null;
        });
    }

    @Test
    public void testCountMethod() {
        FlowManager.databaseForTable(SimpleModel.class, db -> {
            Model.save(SimpleModel.class, new SimpleModel("name"), db);
            Model.save(SimpleModel.class, new SimpleModel("name2"), db);

            Transaction.Builder<Long> builder = db.beginTransactionAsync((Function<DatabaseWrapper, Long>) db1 -> SQLite.selectCountOf(Property.ALL_PROPERTY).from(SimpleModel.class).longValue(db1));
            TransactionObservable.asSingle(builder).subscribe(aLong -> assertEquals(2, aLong.longValue()));
            return null;
        });
    }

    @Test
    public void testInsertMethod() {
        Transaction.Builder<Long> builder = FlowManager.databaseForTable(SimpleModel.class, dbFlowDatabase -> null).beginTransactionAsync(new Function<DatabaseWrapper, Long>() {
            @Override
            public Long apply(DatabaseWrapper db) {
                return SQLite.insert(SimpleModel.class, SimpleModel_Table.name.eq("name")).executeInsert(db);
            }
        });

        TransactionObservable.asSingle(builder).subscribe(aLong -> assertEquals(1, aLong.longValue()));
    }
}
